from datetime import datetime
from typing import List, Optional
import json
import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt

# from common.enums.form_items_key import FormItemsKey
from common.dto.stock_basic_dto import StockBasicDTO
from common.dto.stock_valuation_result_dto import StockValuationResultDTO
# from common.utils.file_reader_utils import read_file_with_fallback


def _get_tushare_token_from_config():
    """从 config.json 文件中加载 tushare_token"""
    try:
        with open("config.json", "r", encoding="utf-8") as f:
            config = json.load(f)
            token = config.get("tushare_token")
            if not token or "your_" in token:
                raise ValueError("Tushare token not configured in config.json")
            return token
    except (FileNotFoundError, json.JSONDecodeError, ValueError) as e:
        print(f"Failed to load tushare token from config.json: {e}")
        return None


# 初始化 Tushare API
tushare_token = _get_tushare_token_from_config()
ts.set_token(tushare_token)
pro = ts.pro_api()


def getDayStock(stockCode: str, startDate: str, endDate: str):
    """
    获取股票或指数的日线数据，根据 stockCode 自动选择接口。
    :param stockCode: 股票或指数代码
    :param startDate: 开始日期 (格式：YYYYMMDD)
    :param endDate: 结束日期 (格式：YYYYMMDD)
    :return: 对应的日线数据
    """
    # 提取市场类型
    if "." not in stockCode:
        raise ValueError(f"无法识别的股票代码格式：{stockCode}")

    market = stockCode.split(".")[-1].upper()

    if market == "SH":
        if stockCode.startswith("000"):
            # 上证/深证指数
            return pro.index_daily(
                ts_code=stockCode, start_date=startDate, end_date=endDate
            )
        else:
            # A股股票
            return pro.daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market == "SZ":
        if stockCode.startswith("399"):
            # 上证/深证指数
            return pro.index_daily(
                ts_code=stockCode, start_date=startDate, end_date=endDate
            )
        else:
            return pro.daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market == "BJ":
        # 北京证券交易所股票
        return pro.daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market == "HK":
        # 港股
        return pro.hk_daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market == "US":
        # 美股
        return pro.us_daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market in ["CSI", "SW", "SI"]:
        # 中证指数、申万行业指数、其他行业指数
        return pro.index_daily(
            ts_code=stockCode, start_date=startDate, end_date=endDate
        )
    elif market in ["CNI", "SZSE", "SSE"]:
        # CNI、SZSE、SSE 渠道指数，统一使用 index_daily 接口
        return pro.index_daily(
            ts_code=stockCode, start_date=startDate, end_date=endDate
        )
    elif market == "ET":
        # ETF 基金
        return pro.fund_daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market in ["IF", "CF"]:
        # 股指期货或商品期货
        return pro.fut_daily(ts_code=stockCode, start_date=startDate, end_date=endDate)
    elif market == "MSC":
        # MSCI 指数
        return pro.index_daily(
            ts_code=stockCode, start_date=startDate, end_date=endDate
        )
    else:
        raise ValueError(f"不支持的市场类型：{market}")


def getRealTime(stockCode):
    return ts.realtime_quote(ts_code=stockCode)


def get_single_stock_basic_info(ts_code: str) -> Optional[StockBasicDTO]:
    """
    获取单个股票的基础信息，并返回一个 DTO 对象。
    :param ts_code: 股票代码
    :return: StockBasicDTO 对象
    """
    # 查询单个股票的基础信息
    stock_basic = pro.stock_basic(
        ts_code=ts_code,
        fields="ts_code,symbol,name,area,industry,cnspell,market,list_date,act_name,act_ent_type",
    )

    # 如果查询结果为空，则返回 None
    if stock_basic.empty:
        return None

    # 取出查询结果并封装为 DTO 对象
    stock = stock_basic.iloc[0]  # 获取第一行（单个股票数据）
    stock_dto = StockBasicDTO(
        ts_code=stock.ts_code,
        symbol=stock.symbol,
        name=stock.name,
        area=stock.area,
        industry=stock.industry,
        cnspell=stock.cnspell,
        market=stock.market,
        list_date=stock.list_date,
        act_name=stock.act_name,
        act_ent_type=stock.act_ent_type,
    )

    return stock_dto


def query_all_stock_info():
    """
    使用 Tushare 查询所有股票基础信息
    """
    try:
        # 查询所有股票基础信息
        df = pro.stock_basic()
        # 转换为字典格式返回
        stock_data_list = df.to_dict(orient="records")
        return stock_data_list
    except Exception as e:
        print(f"查询股票数据时出错: {e}")
        return []


def query_daily_basic(ts_code: str = None, start_date: str = None, end_date: str = None) -> Optional[List[StockValuationResultDTO]]:
    """  
    调用Tushare的 daily_basic 接口获取每日基本面数据  
    包含市盈率、每股收益等关键估值指标。  

    :param ts_code: 股票代码，格式如 '000001.SZ'，为空表示所有股票  
    :param start_date: 开始日期，格式YYYYMMDD  
    :param end_date: 结束日期，格式YYYYMMDD  
    :return: 返回StockValuationResultDTO列表，或者None（异常时）  
    """
    params = {}
    if ts_code:
        params['ts_code'] = ts_code
    if start_date:
        params['start_date'] = start_date
    if end_date:
        params['end_date'] = end_date

    try:
        df = pro.daily_basic(**params)
        if df.empty:
            print(f"未查询到daily_basic数据，参数：{params}")
            return None

        dto_list = []
        for _, row in df.iterrows():
            dto = StockValuationResultDTO(
                ts_code=row['ts_code'],
                trade_date=row['trade_date'],  # 假设日期字段名是trade_date，若不是请对应修改
                close=row.get('close'),
                turnover_rate=row.get('turnover_rate'),
                turnover_rate_f=row.get('turnover_rate_f'),
                volume_ratio=row.get('volume_ratio'),
                pe=row.get('pe'),
                pe_ttm=row.get('pe_ttm'),
                pb=row.get('pb'),
                ps=row.get('ps'),
                ps_ttm=row.get('ps_ttm'),
                dv_ratio=row.get('dv_ratio'),
                dv_ttm=row.get('dv_ttm'),
                total_share=row.get('total_share'),
                float_share=row.get('float_share'),
                free_share=row.get('free_share'),
                total_mv=row.get('total_mv'),
                circ_mv=row.get('circ_mv'),
                notes=None,  # daily_basic接口一般无notes字段，如有可调整
            )
            dto_list.append(dto)
        return dto_list

    except Exception as e:
        print(f"调用 daily_basic 接口失败，参数：{params}，异常：{e}")
        return None
